package com.cxso.example.sdk.http.core;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.cxso.example.sdk.domain.Result;
import com.cxso.example.sdk.http.base.ClientInfo;
import com.cxso.example.sdk.http.base.HttpMethod;
import com.cxso.example.sdk.http.cache.GenericCache;
import com.cxso.example.sdk.http.utils.HttpUtils;
import com.cxso.example.sdk.http.utils.SignUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;

import java.util.HashMap;
import java.util.Map;

public abstract class AbstractClient {

    public final ClientInfo clientInfo;

    public HashMap<String, String> headers;

    public AbstractClient(ClientInfo clientInfo) {
        this.clientInfo = clientInfo;
    }

    protected String rpcInvoke(HttpMethod httpMethod, String path, Object param, Map<String, String> query, Boolean encrypt) {
        try {
            Map<String, String> headers = getHeaders(clientInfo);
            headers.put("Accept", "application/json");
            headers.put("Content-Type", "application/json");

            HttpResponse httpResponse = null;
            switch (httpMethod) {
                case POST:
                    httpResponse = HttpUtils.doPost(clientInfo.getHost(), path, headers, encryptQuery(query, encrypt), JSON.toJSONString(encryptParam(param, encrypt), JSONWriter.Feature.LargeObject));
                    break;
                case GET:
                    httpResponse = HttpUtils.doGet(clientInfo.getHost(), path, headers, encryptQuery(query, encrypt));
                    break;
                case PUT:
                    httpResponse = HttpUtils.doPut(clientInfo.getHost(), path, headers, encryptQuery(query, encrypt), JSON.toJSONString(encryptParam(param, encrypt)));
                    break;
                case DELETE:
                    httpResponse = HttpUtils.doDelete(clientInfo.getHost(), path, headers, encryptQuery(query, encrypt));
                    break;
            }

            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                String jsonStr = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
                if (encrypt) {
                    JSONObject jsonObject = JSONObject.parseObject(jsonStr);
                    Integer code = jsonObject.getInteger("code");
                    String encryptContent = jsonObject.getString("data");
                    if (code == 200 && encryptContent != null) {
                        String res = SignUtils.aesDecrypt(encryptContent, clientInfo.getClientSecret());
                        Object parse = JSON.parse(res);
                        jsonObject.put("data", parse);
                    }
                    return jsonObject.toString();
                }
                return jsonStr;
            } else {
                Result<?> response = Result.fail(httpResponse.getStatusLine().getReasonPhrase());
                return JSON.toJSONString(response);
            }
        } catch (Exception ex) {
            Result<?> response = Result.fail(ex.getMessage());
            return JSON.toJSONString(response);
        }
    }

    private Map<String, String> getHeaders(ClientInfo clientInfo) {
        // 用于请求的头
        Map<String, String> hashMap = new HashMap<>();
        String token = GenericCache.get(clientInfo.getClientId(), clientInfo.getClientSecret());
        if (token != null) {
            hashMap.put("token", token);
        }
        if (headers != null) {
            for (String name : headers.keySet()) {
                hashMap.put(name, headers.get(name));
            }
        }
        hashMap.put("User-Agent", "micro-sdk");
        return hashMap;
    }

    private Map<String, String> encryptQuery(Map<String, String> query, Boolean encrypt) {
        if (query == null) {
            return new HashMap<>();
        }
        if (encrypt) {
            try {
                long timestamp = System.currentTimeMillis();
                String encryptBody = SignUtils.aesEncrypt(JSONObject.toJSONString(query), clientInfo.getClientSecret());
                String sign = SignUtils.signBody(encryptBody, timestamp, clientInfo.getClientRsaPrivateKey());

                Map<String, String> map = new HashMap<>();
                map.put("body", encryptBody);
                map.put("sign", sign);
                map.put("timestamp", String.valueOf(timestamp));
                return map;
            } catch (Exception exception) {
                throw new RuntimeException("加密异常");
            }
        } else {
            return query;
        }
    }

    private Object encryptParam(Object param, Boolean encrypt) {
        if (param == null) {
            return new JSONObject();
        }
        if (encrypt) {
            try {
                long timestamp = System.currentTimeMillis();
                String encryptBody = SignUtils.aesEncrypt(JSONObject.toJSONString(param), clientInfo.getClientSecret());
                String sign = SignUtils.signBody(encryptBody, timestamp, clientInfo.getClientRsaPrivateKey());

                JSONObject request = new JSONObject();
                request.put("body", encryptBody);
                request.put("sign", sign);
                request.put("timestamp", timestamp);
                return request;
            } catch (Exception exception) {
                throw new RuntimeException("加密异常");
            }
        } else {
            return param;
        }
    }
}
